<template>
  <div class="wrap">
    <!-- 这里是工具栏 -->
    <div class="toolbar">
      <!-- 点击事件, 点击icon的时候吸附光标所在位置的标签的所有样式. 并且改变鼠标光标为copy状态, 代表下一次点击将会是给文本赋值样式的操作 -->
      <img src="../images/formatbrush.png" alt="" class="formatbrush" @click="startChangeDom">
      <div class="font_size_dom">
        <div class="title" @click="changeFontSize">{{ currentFontFontSize }}</div>
        <div class="options" v-if="showOption">
          <p v-for="(v, i) in fontSizeArr" :key="i" @click="selectFontSize(v)">{{ v }}</p>
        </div>
      </div>
      <div class="font_family_dom">
        <div class="title" @click="changefont_family">{{ currentFontfont_family }}</div>
        <div class="options" v-if="showfont_familyOption">
          <p v-for="(v, i) in font_familyArr" :key="i" @click="selectfont_family(v)">{{ v }}</p>
        </div>
      </div>
      <div class="color_box">
        <div class="selectColorBox" v-if="showcolorpicker">
          <v-color-picker hide-inputs v-model="userSelect"></v-color-picker>

          <v-btn @click="submitColor">确定</v-btn>
        </div>
        <img src="../images/color.png" alt="" class="colorSelect" @click="showcolorpicker = true">
      </div>

      <p class="func_textstyle" @click="changeTextStyle(1)">粗体</p>
      <p class="func_textstyle" @click="changeTextStyle(2)">斜体</p>
      <p class="func_textstyle" @click="changeTextStyle(3)">删除线</p>
      <p class="func_textstyle" @click="changeTextStyle(4)">下划线</p>
    </div>
    <!-- 其实这里的左右没有实际意义, 只是区分一下有样式和没有样式.  -->
    <div class="fix_css">
      <div class="left_box">
        <p class="style_1">这里是实现功能固定文字部分的div</p>
        <p class="style_2">这里是实现功能固定文字部分的div</p>
        <p class="style_3">这里是实现功能固定文字部分的div</p>
        <p class="style_4">这里是实现功能固定文字部分的div</p>
        <p class="style_5">这里是实现功能固定文字部分的div</p>
        <p class="style_6">这里是实现功能固定文字部分的div</p>
      </div>
      <div class="right_box">
        <p>无样式文字</p>
        <p>无样式文字</p>
        <p>无样式文字</p>
        <p>无样式文字</p>
        <p>无样式文字</p>
        <p>无样式文字</p>
      </div>
    </div>

    <!-- 
      这里有个新的知识点, 就是contenteditable 这个属性会把div变成可编辑状态, 类似于表单的输入框, 但是div的contenteditable 可控性非常强
      富文本类的插件基本都是用contenteditable 
    -->
    <div class="editor" contenteditable id="editor" @focus="handleFocus">

    </div>
  </div>
</template>

<script setup>

import { ref } from 'vue';

// 光标状态
const cursorStatus = ref(false)
// 点击格式刷吸取的样式, 用于给别的文本赋值
const selectedStyles = ref({});

// 点击格式刷的时候执行这个函数
const startChangeDom = () => {

  // 先改变光标代表已经吸取了样式, 下次点击文本是给文本赋值样式(没有实际意义, 只是个标识)
  document.body.style.cursor = 'copy'; // 改变光标样式
  /**
   * 光标状态改为true  因为在点击任意部位文本的时候, 是通过原生的addEventListener 监听整个页面的点击, 
   * 然后判断当下鼠标window.getSelection() 点击位置下的元素是哪个实现的赋值, 所以只有为true的时候会赋值, 也就是吸取完样式的下一次点击
   * 赋值完(也就是格式刷使用完毕) 会改为false 为下一次使用做准备
   * */
  cursorStatus.value = true // 设置光标状态为激活

  // 这个是吸取样式的完整函数
  getSelectedStyles()
}


const getSelectedStyles = () => {
  // 获取当前选中的文本范围 或者就是点一下那一行字就可以, 划词也可以 window.getSelection()这个函数就是专门用于选择光标坐在位置的所有属性
  const selection = window.getSelection();
  // 确保有选中的文本范围
  if (selection.rangeCount > 0) {
    // 获取选中的第一个范围
    const range = selection.getRangeAt(0);
    // 获取选中范围的起始容器的父元素
    const selectedElement = range.startContainer.parentElement;
    // 获取选中元素的计算样式
    const computedStyles = window.getComputedStyle(selectedElement);
    // 定义需要吸取的样式属性列表
    const styleProperties = [
      'font-family', // 字体
      'font-size', // 字体大小
      'font-weight', // 字体粗细
      'color', // 字体颜色
      'text-decoration', // 文本装饰（如下划线）
      'font-style', // 字体样式（如斜体）
      'text-transform', // 文本转换（如大写）
      'letter-spacing', // 字母间距
      'line-height', // 行高
      'text-align' // 文本对齐方式
    ];
    // 遍历样式属性列表并吸取对应的样式值
    styleProperties.forEach(property => {
      selectedStyles.value[property] = computedStyles.getPropertyValue(property);
    });
  }
  // 输出吸取的样式值到控制台
  console.log(selectedStyles.value)
};

/**
 * 将选中的样式应用到指定的元素上
 * @param {HTMLElement} element - 需要应用样式的元素
 */
const applySelectedStyles = (element) => {
  // 输出目标元素到控制台
  console.log(element);
  // 遍历选中的样式属性并应用到目标元素
  Object.keys(selectedStyles.value).forEach(property => {
    // 将选中的样式属性值赋给目标元素的对应样式属性
    element.style[property] = selectedStyles.value[property];
  });
};

// 添加一个点击事件监听器到文档
document.addEventListener('click', (event) => {
  // 检查光标状态是否为真并且点击的目标元素是否为段落元素（<p>）
  if (cursorStatus.value && event.target.className != 'formatbrush'&& event.target.className != 'editor') {
    // 将选中的样式应用到点击的段落元素
    applySelectedStyles(event.target);
    // 重置光标状态为假
    cursorStatus.value = false;
    // 将光标样式重置为默认
    document.body.style.cursor = 'default';
  }
});

// 添加一个鼠标抬起事件监听器到文档
document.addEventListener('mouseup', (event) => {
  // 检查光标状态是否为真并且选中的文本长度大于0
  if (cursorStatus.value && window.getSelection().toString().length > 0) {
    // 获取当前选中的文本范围
    const selection = window.getSelection();
    // 确保有选中的文本范围
    if (selection.rangeCount > 0) {
      // 获取选中的第一个范围
      const range = selection.getRangeAt(0);
      // 获取选中范围的起始容器的父元素
      const selectedElement = range.startContainer.parentElement;
      // 仅应用样式到选中的行
      Object.keys(selectedStyles.value).forEach(property => {
        selectedElement.style[property] = selectedStyles.value[property];
      });
    }
    // 重置光标状态为假
    cursorStatus.value = false;
    // 将光标样式重置为默认
    document.body.style.cursor = 'default';
  }
});

// 定义一个 ref 变量来控制颜色选择器的显示状态
const showcolorpicker = ref(false)
// 定义一个 ref 变量来存储字体大小的数组
const fontSizeArr = ref([
  '12px',
  '13px',
  '14px',
  '15px',
  '16px',
  '19px',
  '22px',
  '24px',
  '29px',
  '32px',
  '40px',
  '48px',
])
const font_familyArr = ref([
  '默认字体',
  'simfang',
  'dingliehakkafont-2',
  'FZCuJinLJW',
  'FZLTZCHJW',
  'FZQingKBYSJW-M',
  'FZSTK',
  'FZYTK',
  '方正字迹-曾正国楷体',
])
// 定义一个 ref 变量来控制字体大小选项的显示状态
const showfont_familyOption = ref(false)
const showOption = ref(false)
// 定义一个 ref 变量来存储当前选中的字体大小
const currentFontFontSize = ref('15px')
const currentFontfont_family = ref('默认字体')

// 定义一个函数来显示字体大小选项
const changeFontSize = () => {
  // 将 showOption 变量设置为 true，显示字体大小选项
  showOption.value = true
}
const changefont_family = () => {
  showfont_familyOption.value = true
}

const selectfont_family = v => {
  currentFontfont_family.value = v
  showfont_familyOption.value = false

  const selection = window.getSelection();
  const anchorNode = selection.anchorNode.parentElement;
  anchorNode.style.fontFamily = v
}
// 定义一个函数来选择字体大小
const selectFontSize = v => {
  // 将 currentFontFontSize 变量设置为选中的字体大小
  currentFontFontSize.value = v
  // 将 showOption 变量设置为 false，隐藏字体大小选项
  showOption.value = false

  // 获取当前选中的文本范围
  const selection = window.getSelection();
  // 获取选中的第一个范围的起始容器的父元素
  const anchorNode = selection.anchorNode.parentElement;
  // 将选中的字体大小应用到起始容器的父元素
  anchorNode.style.fontSize = v
}

// 定义一个 ref 变量来存储用户选择的颜色
const userSelect = ref('')
// 定义一个函数来提交颜色选择
const submitColor = () => {
  // 输出用户选择的颜色到控制台
  console.log(userSelect.value)
  // 将 showcolorpicker 变量设置为 false，隐藏颜色选择器
  showcolorpicker.value = false
  // 获取当前选中的文本范围
  const selection = window.getSelection();
  // 确保有选中的文本范围
  if (selection.rangeCount > 0) {
    // 获取选中的第一个范围
    const range = selection.getRangeAt(0);
    // 获取选中范围的起始容器的父元素
    const selectedElement = range.startContainer.parentElement;
    // 将用户选择的颜色应用到选中行的父元素
    selectedElement.style.color = userSelect.value;
    // 将 text-decoration 的颜色也应用到选中行的父元素
    selectedElement.style.textDecorationColor = userSelect.value;
  }
}

const changeTextStyle = v => {
  const selection = window.getSelection();
  if (!selection.rangeCount) return;

  const range = selection.getRangeAt(0);
  const selectedElement = range.startContainer.parentElement;

  let styleProp, styleValue;

  // 定义样式映射
  switch (v) {
    case 1:
      styleProp = 'fontWeight';
      styleValue = 'bold';
      break;
    case 2:
      styleProp = 'fontStyle';
      styleValue = 'italic';
      break;
    case 3:
      styleProp = 'textDecoration';
      styleValue = 'line-through';
      break;
    case 4:
      styleProp = 'textDecoration';
      styleValue = 'underline';
      break;
    default:
      return;
  }

  // 检查选区所在行的 <p> 标签是否已有目标样式
  const currentStyle = selectedElement.style[styleProp];
  if (currentStyle === styleValue) {
    // 移除样式
    selectedElement.style[styleProp] = '';
  } else {
    // 添加样式
    selectedElement.style[styleProp] = styleValue;
  }
};

function handleFocus() {
  // 如果内容为空，则插入一个默认的 <p> 标签
  if (!document.querySelector('.editor p')) {
    const editor = document.querySelector('.editor');
    const defaultParagraph = document.createElement('p');
    defaultParagraph.innerHTML = '<br>'; // 插入一个空行
    editor.appendChild(defaultParagraph);
  }
}

</script>
<style scoped lang="less">
.wrap {
  width: 1024px;
  height: 100vh;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;

  .toolbar {
    width: 100%;
    height: 50px;
    margin-bottom: 20px;
    border: 1px solid rgba(182, 180, 180, 0.555);
    border-radius: 10px;
    display: flex;
    align-items: center;
    padding: 0 20px;

    .func_textstyle {
      border: 1px solid #b1b0b0;
      color: #696767;
      padding: 3px 10px;
      margin-left: 10px;
      user-select: none;
      /* 禁止选中文本 */
    }

    img {
      width: 30px;
      height: auto;
    }

    .color_box {
      margin-left: 20px;
      position: relative;
      user-select: none;

      /* 禁止选中文本 */
      .selectColorBox {
        position: absolute;
        top: 50px;
      }

      .inputColor {
        position: absolute;
        top: 0;
        widows: 100%;
        opacity: 0;
      }

      .colorSelect {
        width: 30px;
        height: auto;
      }
    }

    .font_size_dom,.font_family_dom {
      width: 100px;
      padding: 3px 5px;
      border: 1px solid #c0c0c0;
      position: relative;
      color: #5c5959;
      text-align: center;
      margin-left: 20px;
      border-radius: 5px;
      user-select: none;
      .title {
        white-space: nowrap;       /* 禁止换行 */
        overflow: hidden;          /* 隐藏超出部分 */
        text-overflow: ellipsis;   /* 显示省略号 */
      }

      /* 禁止选中文本 */
      .options {
        padding: 3px 0px;
        border: 1px solid #c0c0c0;
        position: absolute;
        top: 30px;
        width: 100%;
        left: 0;
        background: #fff;


        p {
          height: 30px;
          text-align: center;
          user-select: none;
          /* 禁止选中文本 */
          white-space: nowrap;       /* 禁止换行 */
          overflow: hidden;          /* 隐藏超出部分 */
          text-overflow: ellipsis;   /* 显示省略号 */
        }

        p:hover {
          background: rgba(172, 171, 171, 0.377);
        }
      }
    }
  }

  .fix_css {
    width: 100%;
    border: 1px solid rgba(182, 180, 180, 0.555);
    height: 260px;
    border-radius: 10px;
    margin-bottom: 20px;
    padding: 10px;
    display: flex;
    justify-content: space-between;

    p {
      margin-bottom: 10px;
    }

    .right_box {
      width: 50%;
      height: 100%;
      margin-left: 20px;
    }

    .left_box {
      width: 50%;
      height: 100%;
    }
  }

  .editor {
    width: 100%;
    border: 1px solid rgba(182, 180, 180, 0.555);
    flex: 1;
    border-radius: 10px;
    padding: 10px;

    p {
      margin-bottom: 10px;
    }
  }
}



/* 样式 1 */
.style_1 {
  font-family: 'Georgia', serif;
  font-size: 18px;
  font-weight: bold;
  color: #ff5733;
  /* 橙色 */
}

/* 样式 2 */
.style_2 {
  font-family: 'Arial', sans-serif;
  font-size: 16px;
  font-weight: normal;
  color: #33a1ff;
  /* 蓝色 */
  text-decoration: underline;
}

/* 样式 3 */
.style_3 {
  font-family: 'Courier New', monospace;
  font-size: 14px;
  font-weight: bold;
  color: #4caf50;
  /* 绿色 */
  letter-spacing: 2px;
}

/* 样式 4 */
.style_4 {
  font-family: 'Verdana', sans-serif;
  font-size: 20px;
  font-weight: lighter;
  color: #9c27b0;
  /* 紫色 */
  text-transform: uppercase;
}

/* 样式 5 */
.style_5 {
  font-family: 'Times New Roman', serif;
  font-size: 22px;
  font-weight: bold;
  color: #ffeb3b;
  /* 黄色 */
  font-style: italic;
}

/* 样式 6 */
.style_6 {
  font-family: 'Comic Sans MS', cursive;
  font-size: 24px;
  font-weight: bold;
  color: #e91e63;
  /* 粉色 */
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
</style>
